package com.im.gateway.tcp;

import com.alibaba.fastjson.JSONObject;
import com.google.protobuf.InvalidProtocolBufferException;
import com.im.common.*;
import com.im.gateway.tcp.service.AuthService;
import com.im.gateway.tcp.util.SpringContextUtil;
import com.im.protocol.*;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.socket.SocketChannel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;

/**
 * @Created leijun
 * @Date 2021/9/11 8:19 上午
 */
@Component
@ChannelHandler.Sharable
public class GatewayTcpHandler extends ChannelInboundHandlerAdapter {

    @Autowired
    private AuthService authService;

    /**
     * 与客户端端断开连接
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        SocketChannel socketChannel = (SocketChannel) ctx.channel();
        SessionManager sessionManager = SessionManager.getInstance();
        // 移除接入层保存的客户端session
        sessionManager.remove(socketChannel);
        // 移除redis保存的分布式session
        Jedis jedis = JedisManager.getJedis();
        String socketChannelId = socketChannel.remoteAddress().getHostName() + ":" + socketChannel.remoteAddress().getPort();
        String sessionKey = "session_" + sessionManager.getUidByChannelId(socketChannelId);
        jedis.del(sessionKey);
        System.out.println("【接入层】与客户端【"+socketChannelId+"】断开连接");
    }

    /**
     * 接收到客户端的请求
     * @param ctx
     * @param msg
     * @throws Exception
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        RequestHandler requestHandler = RequestHandler.getInstance();
        Message message = new Message((ByteBuf) msg);
        if (message.getMessageType() == ImConstant.MESSAGE_TYPE_REQUEST) {
            Request request = message.toRequest();
            if (request.getRequestType() == ImConstant.REQUEST_TYPE_AUTHENTICATE) {
                AuthenticateRequestProto.AuthenticateRequest authenticateRequest =
                        AuthenticateRequestProto.AuthenticateRequest.parseFrom(request.getBody());
                System.out.println("【接入层】接收到客户端：" + authenticateRequest.getUid() + "的认证请求");
                authenticate((SocketChannel) ctx.channel(), request);
            } else if (request.getRequestType() == ImConstant.REQUEST_TYPE_SEND_MESSAGE) {
                MessageRequestProto.MessageRequest messageRequest =
                        MessageRequestProto.MessageRequest.parseFrom(request.getBody());
                requestHandler.sendMessage(messageRequest);
            } else if (request.getRequestType() == ImConstant.REQUEST_TYPE_GROUP_MESSAGE) {
                GroupMessageRequestProto.GroupMessageRequest messageRequest =
                        GroupMessageRequestProto.GroupMessageRequest.parseFrom(request.getBody());
                requestHandler.sendGroupMessage(messageRequest);
            }
        } else if (message.getMessageType() == ImConstant.MESSSAGE_TYPE_RESPONSE) {
            Response response = message.toResponse();
            if (response.getRequestType() == ImConstant.REQUEST_TYPE_PUSH_MESSAGE) {
                PushMessageResponseProto.PushMessageResponse pushMessageResponse =
                        PushMessageResponseProto.PushMessageResponse.parseFrom(response.getBody());
                requestHandler.pushMessageResponse(pushMessageResponse);
            }
        }

        /*byte[] messageBytes = new byte[byteBuf.readableBytes()];
        byteBuf.readBytes(messageBytes);
        String message = new String(messageBytes);
        System.out.println("接收到数据：" + message);

        ClientManager clientManager = ClientManager.getInstance();
        if (message.startsWith("发起用户认证")) {
            String userId = message.split("\\|")[1];
            String token = message.split("\\|")[2];
            clientManager.addChannel(userId, (SocketChannel) ctx.channel());
        } else {
            String userId = message.split("\\|")[1];
            if (!clientManager.exists(userId)) {
                byte[] responseMsg = "未认证用户，不能处理请求".getBytes();
                ByteBuf responseBuf = Unpooled.buffer(responseMsg.length);
                responseBuf.writeBytes(responseMsg);
                ctx.writeAndFlush(responseBuf);
            }
        }*/
    }

    public void authenticate(SocketChannel socketChannel, Request request) throws InvalidProtocolBufferException {
        AuthenticateRequestProto.AuthenticateRequest authenticateRequest =
                AuthenticateRequestProto.AuthenticateRequest.parseFrom(request.getBody());
        AuthenticateResponseProto.AuthenticateResponse.Builder respBuilder =
                AuthenticateResponseProto.AuthenticateResponse.newBuilder();
        try {
            Result result = authService.auth(authenticateRequest.getToken());
            if (result.getCode() == ResponseStatus.SUCCESS.getCode()) {
                // 发送认证请求之后将客户端保存起来
                SessionManager sessionManager = SessionManager.getInstance();
                sessionManager.addSession(authenticateRequest.getUid(), socketChannel);

                String socketChannelId = socketChannel.remoteAddress().getHostName() + ":" + socketChannel.remoteAddress().getPort();
                String sessionKey = "session_"+authenticateRequest.getUid();
                SessionInfo sessionInfo = new SessionInfo();
                sessionInfo.setToken(authenticateRequest.getToken());
                sessionInfo.setTimestamp(authenticateRequest.getTimestamp());
                sessionInfo.setAuthTimestamp(System.currentTimeMillis());
                sessionInfo.setChannelId(socketChannelId);
                JedisManager jedisManager = JedisManager.getInstance();
                jedisManager.getJedis().set(sessionKey, JSONObject.toJSONString(sessionInfo));

                respBuilder.setErrorCode(0);
                respBuilder.setErrorMessage("认证成功");
                respBuilder.setStatus(ResponseCode.OK);
                respBuilder.setUid(authenticateRequest.getUid());
                respBuilder.setToken(authenticateRequest.getToken());
                respBuilder.setTimestamp(authenticateRequest.getTimestamp());
            } else {
                respBuilder.setErrorCode(0);
                respBuilder.setErrorMessage("认证失败");
                respBuilder.setStatus(ResponseCode.ERROR);
            }
        } catch (Exception e) {
            respBuilder.setErrorCode(-1);
            respBuilder.setErrorMessage("认证系统响应失败");
        }
        AuthenticateResponseProto.AuthenticateResponse authenticateResponse = respBuilder.build();
        Response response = new Response(request.getAppSdkVersion(), request.getRequestType(),
                request.getSequence(), authenticateResponse.toByteArray());
        socketChannel.writeAndFlush(response.getBuf());
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        super.channelReadComplete(ctx);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        super.exceptionCaught(ctx, cause);
    }
}
